feat(email): follow-up tracking — flag sent mail awaiting a reply#1916
feat(email): follow-up tracking — flag sent mail awaiting a reply#1916kovtcharov wants to merge 3 commits into
Conversation
) The dropped thread is the inbox's biggest silent failure mode: you send a question, nobody answers, and nothing resurfaces it. The agent can now scan the Sent folder and flag every thread whose newest message is still the user's own once it is older than a configurable window (followup_window_days, default 3 days, or per call) via the new read-only find_awaiting_reply tool — message id, recipient, subject, and age, most overdue first. Detection only, per the #555 boundary: the module imports no send path (the unit tests assert both the module source and the backend transport calls stay read-only), and any actual chaser goes through the confirmation-gated reply tools at the user's request. Gmail-only for now — the Graph backend serves the inbox folder for unrecognized labels, so a Microsoft-only setup gets a loud refusal instead of a silently wrong scan.
|
Verdict: Approve with suggestions — clean, well-tested, well-documented feature. This adds read-only follow-up tracking to the email agent: a new One thing worth a look before merge: the scan only inspects the newest 100 sent messages. Because that list is newest-first, a thread whose last send was months ago and has since been buried past the 100 most-recent sends will never be inspected — which is exactly the "dropped thread you forgot you sent" the feature is meant to catch. For a heavy sender the answer to "what am I still waiting on?" could be quietly incomplete. Not a blocker (the bound is a reasonable interactive ceiling and 🔍 Technical details🟡 ImportantNewest-100 truncation can hide the most-overdue threads ( 🟢 Minor
Strengths
|
TestToolRegistry.test_no_unexpected_tool_set guards against tools that bypass confirmation logic; the new read-only follow-up tracker belongs in its expected set.
…haustiveness The Sent listing is newest-first and capped at 100 stubs, so a heavy sender's oldest — most overdue — threads can fall outside one scan. The result now carries scan_truncated whenever a ceiling was hit (next page token, full listing page, or more threads than max_threads), the tool docstring tells the LLM to relay the incompleteness, and the max_threads cap is tied to DEFAULT_SENT_SCAN_CEILING so the two limits can't drift apart. Raised in the PR #1916 review.
|
Both review points addressed in 6e16e60. The result now carries |
check_followups scans a bounded number of Sent-folder messages per mailbox (default 50, max 200). When a mailbox has more sent mail than that cap, older — potentially overdue — threads go unscanned with no signal that the result is incomplete. The envelope now carries scan_truncated: true whenever the per-mailbox scan hit its cap or the backend reports another page, ported from the parallel implementation in #1916 (find_awaiting_reply) since it doesn't drop naturally out of this branch's own scan design.
|
Closing as superseded by #1922 — both branches independently implement #1606 (follow-up tracking) and cannot merge together (overlapping tooling on the same agent). #1922 was kept for its Gmail+Outlook coverage, comma-safe recipient parsing, and self-mail filtering; the one capability unique to this branch — the |
The unanswered email you forgot you sent is the inbox's biggest silent failure mode — before this, a dropped thread simply disappeared. Now you can ask the email agent "who hasn't replied to me?" and the new read-only
find_awaiting_replytool scans the Sent folder and surfaces every thread still waiting on a response past a configurable window (default 3 days): message id, recipient, subject, and age, most overdue first. Detection only — it never drafts or sends a nudge (autonomous follow-up sending stays with #555, confirmation-gated), and the tests assert the detector touches no send path at all.Scope notes for the reviewer:
POST /v1/email/query); no new REST route, so the REST contract andSCHEMA_VERSIONare unchanged. A deterministic fixed-function route per the feat(email): expose search, pre-scan, archive/quarantine & calendar on the REST contract (schema 2.1) #1883 pattern can ride a follow-up if wanted.specification.htmlcapability matrix updated to match.Test plan
python -m pytest tests/unit/agents/email/ tests/unit/email/ hub/agents/python/email/tests/— 729 passed (the one failure,test_agent_version_matches_package_metadata, is pre-existing local-venv metadata skew and fails identically on clean main)tests/unit/agents/email/test_followup_tracking.py(14 tests) locks the feat(email): follow-up tracking — flag sent mail awaiting a reply #1606 acceptance criteria: replied thread NOT flagged; unreplied flagged only past the window; latest-send-only flagging; nosend_*/draft side effects (transport log + module source); fail-loud on empty user email, bad window, unparseableinternalDate; Microsoft-only refusal; config-window wiring through the registered toolpython util/lint.py --all --fixcleanCloses #1606